<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>watch</title>
</head>
<body>
<div id="app"></div>
<script type="module">
    // watch 和 computed 的区别
    // 1. computed 目的在于计算新值，有缓存
    // 2. watch 目的在于监控属性的变化做某一件事

    import {computed, reactive, effect, watch} from "../js/reactivity/index.js";
    // import {
    //   computed,
    //   reactive,
    //   effect,
    //     watch
    // } from "https://cdn.bootcdn.net/ajax/libs/vue/3.3.4/vue.runtime.esm-browser.prod.js";


    const state = reactive({
        firstName: "j",
        lastName: "w",
        age: 30,
    });

    // ()=>state.firstName 为什么要包装成方法？
    // 因为如果直接写 state.firstName 的话，取的是j这个值，无法监听，所以需要包装成方法，利用effect
    watch(() => state.firstName, (newVal, oldVal) => {
        console.log(newVal, oldVal)
    }, {
        immediate: true
    })

    state.firstName = 'x'

    // 监控输入框的变化，请求接口获取数据显示列表，竟态问题
    // 要求获取接口数据 是最后一次输入框的值（接口有快有慢）

    // watch 大部分的场景可能是，监控数据变化，变化后发送请求
    // 模拟一个输入框的场景，百度搜索框
    // 1 -> 发送请求 2s后才返回
    // 2 -> 发送请求 1s后返回

    // 以最终的1为准，实际上应该用2的结果

    let timer = 4000;

    function getData(data) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(data);
            }, (timer -= 1000));
        });
    }

    let arr = []; // 用于存储上一次的清理操作
    // 什么是闭包?
    // 我定义函数的作用域与执行函数的作用域不是同一个
    watch(
        () => state.age,
        async function (newVal, oldVal, onCleanup) {
            // 自行实现
            // while (arr.length > 0) {
            //   let fn = arr.shift();
            //   fn();
            // }
            let flag = true;
            // arr.push(function () {
            //     flag = false
            // })
            onCleanup(function () {
                // 取消操作 1） 取消请求 2）清理 3）屏蔽
                flag = false;
            });
            let r = await getData(newVal);
            console.log(r)
            flag && (app.innerHTML = r);
        },
        {
            flush: "sync",
        }
    );
    state.age = 100; // 请求3s返回 100
    state.age = 200; // 请求2s返回 200
    state.age = 300; // 请求1s返回 300

</script>
</body>
</html>
